/*
 * Copyright (c) 2015. For Intelligent Group.
 */


package com.intelligent.ispc.foundation.mail;


import com.google.common.collect.Maps;
import com.intelligent.ispc.common.utils.ApplicationException;
import com.intelligent.ispc.common.utils.ExceptionMessages;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.task.TaskExecutor;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Properties;


/**
 * Created by Julia.Zhou on 2015/12/7.
 */
public class MailSender
{
    private static final String DEFAULT_ENCODING = "utf-8";

    private static final String MAIL_BUSINESS_TEMPLATE = "defaultTemplate.ftl";

    private static Logger LOGGER = LoggerFactory.getLogger(MailSender.class);

    private Template template;

    private TaskExecutor taskExecutor;

    private JavaMailSender	mailSender;

    private JavaMailSender setMailSenderValues(MailConfiguration emailConfiguration){
        LOGGER.info("Send mail emailConfiguration={}", emailConfiguration);
        JavaMailSenderImpl mailSender1 = (JavaMailSenderImpl)mailSender;
        mailSender1.setHost(emailConfiguration.getHostAddress());
        mailSender1.setPort(emailConfiguration.getPort());
        mailSender1.setUsername(emailConfiguration.getUsername());
        mailSender1.setPassword(emailConfiguration.getPassword());

        mailSender1.setProtocol(emailConfiguration.getProtocol());
        mailSender1.setDefaultEncoding(DEFAULT_ENCODING);

        Properties javaMailProperties = new Properties();
        javaMailProperties.put("mail.smtp.auth","true");
        //javaMailProperties.put("mail.smtp.ssl.enable",emailDto.getIsTLS());
        javaMailProperties.put("mail.smtp.connectiontimeout",emailConfiguration.getTimeout());
        mailSender1.setJavaMailProperties(javaMailProperties);
        return mailSender1;
    }

    /**
     * Send notification messages in MIME format.
     */
    public void sendMail(final MailDto targetDTO, MailConfiguration emailConfiguration)
    {
        taskExecutor.execute(new Thread() {
            public void run()
            {
                try {
                    if (targetDTO == null || emailConfiguration == null) {
                        throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
                    }
                    JavaMailSender mailSender1 = setMailSenderValues(emailConfiguration);
                    MimeMessage msg = mailSender1.createMimeMessage();
                    MimeMessageHelper helper = new MimeMessageHelper(msg, true, DEFAULT_ENCODING);

                    helper.setFrom(emailConfiguration.getSendAddress());
                    helper.setTo(targetDTO.getTargetAddress());

                    if (targetDTO.getUsingDefault()) {
                        helper.setText(generateContent(targetDTO), true);
                    }
                    else {
                        helper.setText(targetDTO.getContent(), true);
                    }
                    if (targetDTO.getSubject() != null) {
                        helper.setSubject(targetDTO.getSubject());
                    }
                    mailSender1.send(msg);
                    LOGGER.info("Send mail success!");
                }
                catch (MessagingException e) {
                    LOGGER.error("Building mail failed!", e);
                }
                catch (Exception e) {
                    LOGGER.error("Send mail failed!", e);
                }
            }
        });
    }

    /**
     * Asynchronous sending MIME format the user to modify the notification message.
     */
    public void sendMailAsynchronously(final List<MailDto> mailDTOs, MailConfiguration emailConfiguration)
    {
        for (MailDto target : mailDTOs) {
            sendMail(target, emailConfiguration);
        }
    }

    /**
     * Asynchronous sending MIME format the user to modify the notification message.
     */
    public void sendMailAsynchronously(final MailDto mailDTO, MailConfiguration emailConfiguration)
    {
        sendMail(mailDTO, emailConfiguration);
    }

    /**
     * Use Freemarker generate html-formatted content.
     */
    private String generateContent(MailDto targetDTO) throws MessagingException
    {
        try {
            Map context = Maps.newConcurrentMap();
            context.put("mailDTO", targetDTO);

            return FreeMarkerTemplateUtils.processTemplateIntoString(template, context);
        }
        catch (IOException e) {
            LOGGER.error("Generate content failed, the FreeMarker template cannot be found.", e);
            throw new ApplicationException("The FreeMarker template cannot be found.", e);
        }
        catch (TemplateException e) {
            LOGGER.error("Generate content failed, build the FreeMarker failed.", e);
            throw new ApplicationException(" Build the FreeMarker failed.", e);
        }
    }

    /**
     * Freemarker injection engine configuration, structure Freemarker mail content templates..
     */
    public void setFreemarkerConfiguration(Configuration freemarkerConfiguration) throws IOException
    {
        template = freemarkerConfiguration.getTemplate(MAIL_BUSINESS_TEMPLATE, DEFAULT_ENCODING);
    }

    public void testEmail(final MailDto targetDTO, MailConfiguration emailConfiguration)
    {
        try {
            if (targetDTO == null || emailConfiguration == null) {
                throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
            }

            JavaMailSender mailSender1 = setMailSenderValues(emailConfiguration);
            MimeMessage msg = mailSender1.createMimeMessage();
            MimeMessageHelper helper = new MimeMessageHelper(msg, true, DEFAULT_ENCODING);

            helper.setFrom(emailConfiguration.getSendAddress());
            helper.setTo(targetDTO.getTargetAddress());
            helper.setSubject(targetDTO.getSubject());
            helper.setText(targetDTO.getContent(), true);
            mailSender1.send(msg);
            LOGGER.info("Send mail success!");
        }
        catch (MessagingException e) {
            LOGGER.error("Building mail failed!", e);
            throw new ApplicationException(e);
        }
        catch (Exception e) {
            LOGGER.error("Send mail failed!", e);
            throw new ApplicationException(e);
        }
    }

    public void setTaskExecutor(TaskExecutor taskExecutor)
    {
        this.taskExecutor = taskExecutor;
    }

    public void setMailSender(JavaMailSender mailSender)
    {
        this.mailSender = mailSender;
    }
}
